home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 December / PCWorld_2005-12_cd.bin / software / temacd / tiny / tpf-6[1].5.126.exe / Tiny Firewall 2005.msi / webui.dll / REPORTS / LOG.XSL < prev    next >
Encoding:
Extensible Markup Language  |  2005-08-17  |  36.7 KB  |  462 lines

  1.  ■<?xml version='1.0' ?>
  2. <!--
  3. /*//////////////////////////////////////////////////////////////////////
  4. Filename:          log.xsl
  5. Company Name:      Computer Associates International, Inc.
  6. Legal Copyright: Copyright (c) Computer Associates International, Inc.
  7. Author:          Jozef Palocko
  8. Product:          Tiny Firewall
  9. Description:      Log analyzer stylesheet
  10. Changelog:    
  11.     18.8.2003 - added displaying date in local time zone
  12. ///////////////////////////////////////////////////////////////////////*/
  13.  -->
  14. <xsl:stylesheet version="1.0" 
  15.     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  16.     xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  17.     xmlns:time="http://mycompany.com/mynamespace">
  18. <msxsl:script language="JScript" implements-prefix="time">
  19.   <![CDATA[
  20.      function LocalTime(node)
  21.    {
  22.        nd = node.nextNode();
  23.         t = new Date(Date.parse(nd.getAttribute("dateTimeLast")));
  24.        return t.toLocaleString( );
  25.    }
  26.    ]]>
  27. </msxsl:script>
  28. <xsl:variable name="Filter" select="//Root/Params/Filter"/>
  29. <xsl:variable name="Def" select="document($Filter//fncidsfile)"/>
  30.  <!--
  31.  //////////////////////////////////////
  32.  ///////// Named filter templates
  33.  -->
  34.     <!-- ///////// tplModule //////////// -->
  35.     <xsl:template name="tplModule" >
  36.         <xsl:param name="Events"/>
  37.         <xsl:choose>
  38.             <xsl:when test='$Filter//module="1"'>
  39.                 <xsl:call-template name="tplObject">
  40.                     <xsl:with-param name="Events" select='$Events[@module = "Windows Security" ]'/>
  41.                 </xsl:call-template>
  42.             </xsl:when>
  43.             <xsl:when test='$Filter//module="2"'>
  44.                 <xsl:call-template name="tplDirection">
  45.                     <xsl:with-param name="Events" select='$Events[@module = "Firewall" ]'/>
  46.                 </xsl:call-template>
  47.             </xsl:when>
  48.             <xsl:when test='$Filter//module="16"'>
  49.                 <xsl:call-template name="tplMessage">
  50.                     <xsl:with-param name="Events" select='$Events[@module = "IDS" ]'/>
  51.                 </xsl:call-template>
  52.             </xsl:when>
  53.             <xsl:otherwise>
  54.                 <xsl:call-template name="tplAr">
  55.                     <xsl:with-param name="Events"  select="$Events"/>
  56.                 </xsl:call-template>
  57.             </xsl:otherwise>
  58.         </xsl:choose>
  59.     </xsl:template>
  60.     <!-- ///////// tplObject //////////// -->
  61.     <xsl:template name="tplObject" >
  62.         <xsl:param name="Events"/>
  63.         <xsl:choose>
  64.             <xsl:when test="$Filter//string=''">
  65.                 <xsl:call-template name="tplAr">
  66.                     <xsl:with-param name="Events" select="$Events"/>
  67.                 </xsl:call-template>
  68.             </xsl:when>
  69.             <xsl:otherwise>
  70.                 <xsl:call-template name="tplAr">
  71.                     <xsl:with-param name="Events" select="$Events[contains(
  72.                             translate( Object, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  73.                             translate($Filter//string,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  74.                 </xsl:call-template>
  75.             </xsl:otherwise>
  76.         </xsl:choose>
  77.     </xsl:template>
  78.     <!-- ///////// tplMessage //////////// -->
  79.     <xsl:template name="tplMessage" >
  80.         <xsl:param name="Events"/>
  81.         <xsl:choose>
  82.             <xsl:when test="$Filter//string=''">
  83.                 <xsl:call-template name="tplAr">
  84.                     <xsl:with-param name="Events" select="$Events"/>
  85.                 </xsl:call-template>
  86.             </xsl:when>
  87.             <xsl:otherwise>
  88.                 <xsl:call-template name="tplAr">
  89.                     <xsl:with-param name="Events" select="$Events[contains(
  90.                             translate( Msg, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  91.                             translate($Filter//string,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  92.                 </xsl:call-template>
  93.             </xsl:otherwise>
  94.         </xsl:choose>
  95.     </xsl:template>
  96.     <!-- ///////// tplDirection //////////// -->
  97.     <xsl:template name="tplDirection" >
  98.         <xsl:param name="Events"/>
  99.         <xsl:choose>
  100.             <xsl:when test="$Filter//direction=''">
  101.                 <xsl:call-template name="tplProtocol">
  102.                     <xsl:with-param name="Events" select="$Events"/>
  103.                 </xsl:call-template>
  104.             </xsl:when>
  105.             <xsl:otherwise>
  106.                 <xsl:call-template name="tplProtocol">
  107.                     <xsl:with-param name="Events" select="$Events[InetDef/@dir = $Filter//direction]"/>
  108.                 </xsl:call-template>
  109.             </xsl:otherwise>
  110.         </xsl:choose>
  111.     </xsl:template>
  112.     <!-- ///////// tplProtocol //////////// -->
  113.     <xsl:template name="tplProtocol" >
  114.         <xsl:param name="Events"/>
  115.         <xsl:choose>
  116.             <xsl:when test="$Filter//protocol=''">
  117.                 <xsl:call-template name="tplIPAddress">
  118.                     <xsl:with-param name="Events" select="$Events"/>
  119.                 </xsl:call-template>
  120.             </xsl:when>
  121.             <xsl:otherwise>
  122.                 <xsl:call-template name="tplIPAddress">
  123.                     <xsl:with-param name="Events" select="$Events[contains(InetDef/@prot , $Filter//protocol)]"/>
  124.                 </xsl:call-template>
  125.             </xsl:otherwise>
  126.         </xsl:choose>
  127.     </xsl:template>
  128.     <!-- ///////// tplIPAddress //////////// -->
  129.     <xsl:template name="tplIPAddress" >
  130.         <xsl:param name="Events"/>
  131.         <xsl:choose>
  132.             <xsl:when test="$Filter//ip=''">
  133.                 <xsl:call-template name="tplRemPort">
  134.                     <xsl:with-param name="Events" select="$Events"/>
  135.                 </xsl:call-template>
  136.             </xsl:when>
  137.             <xsl:otherwise>
  138.                 <xsl:call-template name="tplRemPort">
  139.                     <xsl:with-param name="Events" select="$Events[contains(
  140.                             translate( InetDef/@remIp, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  141.                             translate($Filter//ip,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  142.                 </xsl:call-template>
  143.             </xsl:otherwise>
  144.         </xsl:choose>
  145.     </xsl:template>
  146.     <!-- ///////// tplRemPort //////////// -->
  147.     <xsl:template name="tplRemPort" >
  148.         <xsl:param name="Events"/>
  149.         <xsl:choose>
  150.             <xsl:when test="$Filter//remport=''">
  151.                 <xsl:call-template name="tplLocPort">
  152.                     <xsl:with-param name="Events" select="$Events"/>
  153.                 </xsl:call-template>
  154.             </xsl:when>
  155.             <xsl:otherwise>
  156.                 <xsl:call-template name="tplLocPort">
  157.                     <xsl:with-param name="Events" select="$Events[InetDef/@remPort = $Filter//remport]"/>
  158.                 </xsl:call-template>
  159.             </xsl:otherwise>
  160.         </xsl:choose>
  161.     </xsl:template>
  162.     <!-- ///////// tplLocPort //////////// -->
  163.     <xsl:template name="tplLocPort" >
  164.         <xsl:param name="Events"/>
  165.         <xsl:choose>
  166.             <xsl:when test="$Filter//locport=''">
  167.                 <xsl:call-template name="tplAr">
  168.                     <xsl:with-param name="Events"  select="$Events"/>
  169.                 </xsl:call-template>
  170.             </xsl:when>
  171.             <xsl:otherwise>
  172.                 <xsl:call-template name="tplAr">
  173.                     <xsl:with-param name="Events" select="$Events[InetDef/@locPort = $Filter//locport]"/>
  174.                 </xsl:call-template>
  175.             </xsl:otherwise>
  176.         </xsl:choose>
  177.     </xsl:template>
  178.     <!-- ///////// tpl access result //////////// -->
  179.     <xsl:template name="tplAr" >
  180.         <xsl:param name="Events"/>
  181.         <xsl:choose>
  182.             <xsl:when test="$Filter//ar=''">
  183.                 <xsl:call-template name="tplApplication">
  184.                     <xsl:with-param name="Events" select="$Events"/>
  185.                 </xsl:call-template>
  186.             </xsl:when>
  187.             <xsl:otherwise>
  188.                 <xsl:call-template name="tplApplication">
  189.                     <xsl:with-param name="Events"  select="$Events[Action = $Filter//ar]"/>
  190.                 </xsl:call-template>
  191.             </xsl:otherwise>
  192.         </xsl:choose>
  193.     </xsl:template>
  194.     <!-- ///////// tplApplication result //////////// -->
  195.     <xsl:template name="tplApplication" >
  196.         <xsl:param name="Events"/>
  197.         <xsl:choose>
  198.             <xsl:when test="$Filter//app=''">
  199.                 <xsl:call-template name="tplUser">
  200.                     <xsl:with-param name="Events" select="$Events"/>
  201.                 </xsl:call-template>
  202.             </xsl:when>
  203.             <xsl:otherwise>
  204.                 <xsl:call-template name="tplUser">
  205.                     <xsl:with-param name="Events" select="$Events[contains(
  206.                             translate( App, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  207.                             translate($Filter//app, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  208.                 </xsl:call-template>
  209.             </xsl:otherwise>
  210.         </xsl:choose>
  211.     </xsl:template>
  212.     <!-- ///////// tplUser result //////////// -->
  213.     <xsl:template name="tplUser" >
  214.         <xsl:param name="Events"/>
  215.         <xsl:choose>
  216.             <xsl:when test="$Filter//user=''">
  217.                 <!-- should never occur -->
  218.                 <xsl:call-template name="tplDomain">
  219.                     <xsl:with-param name="Events" select="$Events"/>
  220.                 </xsl:call-template>
  221.             </xsl:when>
  222.             
  223.             <xsl:when test="$Filter//user='All Users (*)'">
  224.                 <xsl:choose>
  225.                 <xsl:when test="$Filter//sort='App'">
  226.                 
  227.                     <xsl:variable name="EventsSortedByApp" select="$Events[     not(@module='IDS') and not(App=preceding-sibling::Event/App) or
  228.                                                             not(@module=preceding-sibling::Event/@module) or
  229.                                                             not(count(@domain)=0) and not(@domain=preceding-sibling::Event/@domain) or
  230.                                                             @module='IDS' and not(Msg=preceding-sibling::Event/Msg) or
  231.                                                             not(Action/@ar=preceding-sibling::Event/Action/@ar) or
  232.                                                             @module='Firewall' and not (
  233.                                                                         InetDef/@prot=preceding-sibling::Event/InetDef/@prot and
  234.                                                                         (count(InetDef/@dir)=0 or InetDef/@dir=preceding-sibling::Event/InetDef/@dir) and
  235.                                                                         (count(InetDef/@remPort)=0 or InetDef/@remPort=preceding-sibling::Event/InetDef/@remPort) and
  236.                                                                         (count(InetDef/@remIp)=0 or InetDef/@remIp=preceding-sibling::Event/InetDef/@remIp)
  237.                                                                            )
  238.                                                         ]"/>
  239.                                                         
  240.                     <xsl:call-template name="sortEvents">
  241.                         <xsl:with-param name="Events" select="$EventsSortedByApp"/>
  242.                         <xsl:with-param name="OrigEvents" select="$Events"/>
  243.                     </xsl:call-template>
  244.                     
  245. <!--                    <xsl:apply-templates select='$Events[     not(@module="IDS") and not(App=preceding-sibling::Event/App) or
  246.                                                             not(@module=preceding-sibling::Event/@module) or
  247.                                                             not(count(@user)=0) and not(@user=preceding-sibling::Event/@user) or
  248.                                                             not(count(@domain)=0) and not(@domain=preceding-sibling::Event/@domain) or
  249.                                                             @module="IDS" and not(Msg=preceding-sibling::Event/Msg) or
  250.                                                             not(Action=preceding-sibling::Event/Action) or
  251.                                                             @module="Firewall" and not (
  252.                                                                         InetDef/@prot=preceding-sibling::Event/InetDef/@prot and
  253.                                                                         (count(InetDef/@dir)=0 or InetDef/@dir=preceding-sibling::Event/InetDef/@dir) and
  254.                                                                         (count(InetDef/@remPort)=0 or InetDef/@remPort=preceding-sibling::Event/InetDef/@remPort) and
  255.                                                                         (count(InetDef/@remIp)=0 or InetDef/@remIp=preceding-sibling::Event/InetDef/@remIp)
  256.                                                                            )
  257.                                                         ]'>
  258.                         <xsl:with-param name="Total" select="count($Events)"/>
  259.                         <xsl:with-param name="Events" select="$Events"/>
  260.                         <xsl:sort select="App" order="ascending"/>
  261.                         <xsl:sort select="@module" order="ascending"/>
  262.                         <xsl:sort select="@user" order="ascending"/>
  263.                         <xsl:sort select="@domain" order="ascending"/>
  264.                         <xsl:sort select="Object" order="ascending"/>
  265.                         <xsl:sort select="Msg" order="ascending"/>
  266.                         <xsl:sort select="Action" order="ascending"/>
  267.                         <xsl:sort select="InetDef/@dir" order="ascending"/>
  268.                         <xsl:sort select="InetDef/@remIp" order="ascending"/>
  269.                         <xsl:sort select="InetDef/@LocIp" order="ascending"/>
  270.                     </xsl:apply-templates>-->
  271.                 </xsl:when>
  272.                 <xsl:otherwise>
  273.                     <xsl:call-template name="sortEvents">
  274.                         <xsl:with-param name="Total" select="count($Events)"/>
  275.                         <xsl:with-param name="Events" select="$Events"/>
  276.                     </xsl:call-template>
  277.                     
  278.                 </xsl:otherwise>
  279.                 </xsl:choose>
  280.             </xsl:when>
  281.             <xsl:otherwise>
  282.                 <xsl:call-template name="tplDomain">
  283.                     <xsl:with-param name="Events" select="$Events[@module='IDS' or contains(
  284.                         translate( @user, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  285.                         translate($Filter//user,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  286.                 </xsl:call-template>
  287.             </xsl:otherwise>
  288.         </xsl:choose>
  289.     </xsl:template>
  290.     <!-- ///////// tplDomain result //////////// -->
  291.     <xsl:template name="tplDomain" >
  292.         <xsl:param name="Events"/>
  293.         <xsl:variable name="EventsSortedByApp" select="$Events[     not(@module='IDS') and not(App=preceding-sibling::Event/App) or
  294.                                                             not(@module=preceding-sibling::Event/@module) or
  295.                                                             not(count(@domain)=0) and not(@domain=preceding-sibling::Event/@domain) or
  296.                                                             @module='IDS' and not(Msg=preceding-sibling::Event/Msg) or
  297.                                                             not(Action/@ar=preceding-sibling::Event/Action/@ar) or
  298.                                                             @module='Firewall' and not (
  299.                                                                         InetDef/@prot=preceding-sibling::Event/InetDef/@prot and
  300.                                                                         (count(InetDef/@dir)=0 or InetDef/@dir=preceding-sibling::Event/InetDef/@dir) and
  301.                                                                         (count(InetDef/@remPort)=0 or InetDef/@remPort=preceding-sibling::Event/InetDef/@remPort) and
  302.                                                                         (count(InetDef/@remIp)=0 or InetDef/@remIp=preceding-sibling::Event/InetDef/@remIp)
  303.                                                                            )
  304.                                                         ]"/>
  305.         <xsl:choose>
  306.             <xsl:when test="$Filter//domain=''">
  307.                 <!-- domain filter is empty -->
  308.                 <xsl:choose>
  309.                 <xsl:when test="$Filter//sort='App'">
  310.                     <!-- xx -->
  311.                     <xsl:call-template name="sortEvents">
  312.                         <xsl:with-param name="Events" select="$EventsSortedByApp"/>
  313.                         <xsl:with-param name="OrigEvents" select="$Events"/>
  314.                     </xsl:call-template>
  315.                     
  316. <!--                    <xsl:apply-templates select="$EventsSortedByApp">
  317.                         <xsl:with-param name="Total" select="count($Events)"/>
  318.                         <xsl:with-param name="Events" select="$Events"/>
  319.                         <xsl:sort select="App" order="ascending"/>
  320.                         <xsl:sort select="@domain" order="ascending"/>
  321.                         <xsl:sort select="@module" order="ascending"/>
  322.                         <xsl:sort select="Object" order="ascending"/>
  323.                         <xsl:sort select="Msg" order="ascending"/>
  324.                         <xsl:sort select="Action" order="ascending"/>
  325.                         <xsl:sort select="InetDef/@dir" order="ascending"/>
  326.                         <xsl:sort select="InetDef/@remIp" order="ascending"/>
  327.                         <xsl:sort select="InetDef/@LocIp" order="ascending"/>
  328.                     </xsl:apply-templates>-->
  329.                 </xsl:when>
  330.                 <xsl:otherwise>
  331.                     <xsl:call-template name="sortEvents">
  332.                         <xsl:with-param name="Total" select="count($Events)"/>
  333.                         <xsl:with-param name="Events" select="$Events"/>
  334.                     </xsl:call-template>
  335.                 </xsl:otherwise>
  336.                 </xsl:choose>
  337.             </xsl:when>
  338.             <xsl:otherwise>
  339.                 <!-- domain filter is not empty -->
  340.                 <xsl:choose>
  341.                     <xsl:when test="$Filter//sort='App'">
  342.                         <xsl:variable name="selected_events" select="$EventsSortedByApp[contains(
  343.                             translate( @domain, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  344.                             translate($Filter//domain,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  345.                             
  346.                         <xsl:call-template name="sortEvents">
  347.                             <xsl:with-param name="Events" select="$selected_events"/>
  348.                             <xsl:with-param name="OrigEvents" select="$Events[contains(
  349.                                 translate( @domain, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  350.                                 translate($Filter//domain,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  351.                         </xsl:call-template>
  352.                             
  353.                         <!--<xsl:apply-templates select="$selected_events">
  354.                             <xsl:with-param name="Total" select="count($selected_events)"/> -->
  355.                             <!-- count all events from this user and domain, not sorted by app -->
  356.                             <!--<xsl:with-param name="Events" select="$Events[contains(
  357.                             translate( @domain, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  358.                             translate($Filter//domain,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  359.                             
  360.                             <xsl:sort select="App" order="ascending"/>
  361.                             <xsl:sort select="@domain" order="ascending"/>
  362.                             <xsl:sort select="@module" order="ascending"/>
  363.                             <xsl:sort select="Object" order="ascending"/>
  364.                             <xsl:sort select="Msg" order="ascending"/>
  365.                             <xsl:sort select="Action" order="ascending"/>
  366.                             <xsl:sort select="InetDef/@dir" order="ascending"/>
  367.                             <xsl:sort select="InetDef/@remIp" order="ascending"/>
  368.                             <xsl:sort select="InetDef/@LocIp" order="ascending"/>
  369.                         </xsl:apply-templates>-->
  370.                     </xsl:when>
  371.                     <xsl:otherwise>
  372.                             <xsl:variable name="selected_events" select="$Events[   @module='IDS' or contains(
  373.                             translate( @domain, '_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' , '_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'),
  374.                             translate($Filter//domain,'_-\/.:;,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789','_-\/.:;,abcdefghijklmnopqrstuvwxyz0123456789'))]"/>
  375.                             <xsl:call-template name="sortEvents">
  376.                                 <xsl:with-param name="Events" select="$selected_events"/>
  377.                             </xsl:call-template>
  378.                             
  379. <!--                            <xsl:apply-templates select="$selected_events">
  380.                                 
  381.                                 <xsl:sort select="@count" order="descending"/>
  382.                             
  383.                                 <xsl:with-param name="Total" select="count($selected_events)"/>
  384.                             </xsl:apply-templates>-->
  385.                     </xsl:otherwise>
  386.                 </xsl:choose>
  387.             </xsl:otherwise>
  388.         </xsl:choose>
  389.     </xsl:template>
  390.     
  391.     <xsl:template name="sortEvents">
  392.         <xsl:param name="Events"/>
  393.         <xsl:param name="OrigEvents"/>
  394.         
  395.         <xsl:variable name="sortParamNoDir">
  396.             <xsl:choose>
  397.                 <xsl:when test="starts-with($Filter//sort,'-')">
  398.                     <xsl:value-of select="substring-after($Filter//sort, '-')"/>
  399.                 </xsl:when>
  400.                 <xsl:otherwise>
  401.                     <xsl:value-of select="$Filter//sort"/>
  402.                 </xsl:otherwise>
  403.             </xsl:choose>
  404.         </xsl:variable>
  405.         
  406.         <xsl:variable name="sortAtr">
  407.             <xsl:choose>
  408.                 <xsl:when test="$Filter//sort='App' or $Filter//sort='-App'"></xsl:when>
  409.                 <xsl:otherwise><xsl:value-of select="$sortParamNoDir"/></xsl:otherwise>
  410.             </xsl:choose>
  411.         </xsl:variable>
  412.         <xsl:variable name="sortNode">
  413.             <xsl:choose>
  414.                 <xsl:when test="$Filter//sort='App' or $Filter//sort='-App'">App</xsl:when>
  415.                 <xsl:otherwise></xsl:otherwise>
  416.             </xsl:choose>
  417.         </xsl:variable>
  418.         <xsl:variable name="sortDir">
  419.             <xsl:choose>
  420.                 <xsl:when test="starts-with($Filter//sort,'-')">ascending</xsl:when>
  421.                 <xsl:otherwise>descending</xsl:otherwise>
  422.             </xsl:choose>
  423.         </xsl:variable>
  424.         
  425.         <xsl:apply-templates select="$Events">
  426.             <xsl:sort select="@*[name()=$sortAtr] | Action/@*[name()=$sortAtr]" order="{$sortDir}"/>
  427.             <xsl:sort select="*[name()=$sortNode]" order="{$sortDir}"/>
  428.             <xsl:sort select="@dateTimeLast" order="{$sortDir}"/>
  429.             
  430.             <xsl:with-param name="Events" select="$OrigEvents"/>
  431.         </xsl:apply-templates>
  432.     </xsl:template>
  433. </xsl:stylesheet>